-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP]: Shadow dom rfc #7687
base: main
Are you sure you want to change the base?
[WIP]: Shadow dom rfc #7687
Conversation
rfcs/2025-shadow-dom-support.md
Outdated
|
||
## Motivation | ||
|
||
As Web Components have become more prominent and more libraries and applications use them, we have encountered friction for people trying to adopt or use our libraries alongside others. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use case is beyond web components. For example, 3rd party widgets or SDKs who do not want their styles to be affected by user's website code may want to use shadow DOM without web components. This is what we do. The other option for such apps is dynamic iframes. The good thing is that with the changes we make for shadow DOM, we automatically take care of dynamic iframes too by using the correct document
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I'll reframe a bit, I was using Web Components as a bit of a stand-in term for shadow dom, but this is more accurate
I think we are potentially over simplifying by stating that solving shadow dom will solve iframes. They are two fundamentally different technologies even if they have overlap in terms of problems they solve.
See for example the need for
addWindowFocusTracking(iframeRoot); |
This is not needed for Shadow DOM. If we only worked on supporting Shadow DOM, this would be missed. That is because events inside an iframe will not appear outside the frame. While for Shadow DOM, events still have a capture phase and bubble phase outside of the Shadow root.
There will be other cases where behaviour differs between the two technologies.
|
||
As mentioned earlier, there are proposed parts to this initiative: | ||
|
||
1. Custom React Testing Library Renderer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not write special tests for shadow DOM. All our component testing is done using playwright's component testing. We run the same tests both with and without shadow DOM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what this comment has to do with us? The RFC is for what we need to do to support shadow dom in our library.
I'm also suggesting that we run the same tests both with and without shadow DOM
we should create a custom React Testing Library renderer for our unit tests which can wrap each test's rendered dom in a shadow root.
... without needing to write many specific tests.
There will need to be specific tests as well, but they can be added as edge cases are discovered. For now I'd like to get all of our current tests running both ways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what this comment has to do with us?
Not much. This was just me sharing how we handle this situation.
|
||
In addition, contributions may occur for a little while until those teams have their needs met. However, it should be assumed that there will be further work to complete the goals as outlined here. | ||
|
||
Another concern is that the current approach is, for lack of a better word, hacky. This is because we are accessing and manipulating the Shadow DOM in ways that it wasn't really intended. If we were to rewrite our library today, there are other ways we'd solve these issues which would respect more of the concept of the Shadow DOM and its purpose. What we do here and now may complicate a future where we have different APIs to support this vision of what support would ideally look like. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think one way to think about this is supporting different root elements instead of just think about it as shadow DOM support. See #7743 for example. Components like modal and popover always treat document.body as their root element. Instead react-aria should provide options to treat any other element as a container element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly, what happens in the case of nested shadow doms though? Would we expect people to addWindowFocusTracking
equivalent for each root and each hook/function that needs it? Would components need to accept a root element to pass down to hooks? context?
This wouldn't work for closed roots. This is why we want to re-think some of the ways parts of our library work. For example, FocusScope moves focus around for you when it's contain=true
. This can't move into closed shadow roots, which is why the video
tag breaks our FocusScope at the moment in certain cases. Instead, if we moved to a sentinel-based approach, we could let the browser handle the tab movement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially I thought that supporting closed shadow root might not be a high priority at the beginning but you raised a good point about the video
element. In that case, we do need to support both modes of shadow root.
Would we expect people to addWindowFocusTracking equivalent for each root and each hook/function that needs it? Would components need to accept a root element to pass down to hooks? context?
This might not be a good solution in the long run. But I can't answer much right now before going into the details of closed shadow root.
|
||
## Open Questions | ||
|
||
* How to actually define the limitations of our support? See Introduction, it's missing a final sentence with this information. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the best way to approach it is to come up with a setup where all new code is compatible and the existing code can be changed when someone needs it. I think in a while, it will be just about using a set of utilities.
We can start with the getOwnerWindow and getOwnerDocument eslint rule in more packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is ambiguous
all new code is compatible
Does that mean it works in an application that has a single shadow dom at the root? that it can use video
anywhere? that it can have 3rd party web components anywhere? that it can have shadow roots anywhere?
What if the new code is a new feature in an existing component or hook that has no support? what if that hook depends on lower hooks that don't have support and changing those hooks would also change how other components work.
It's a lofty goal and I think we should aim for support of everything. But it has to be moderated with the cost of implementation and ongoing support.
I don't believe this is true
it will be just about using a set of utilities
as I mentioned earlier, in order to support closed root (as an example), we have to rethink how many components and hooks are implemented.
I agree with this
We can start with the getOwnerWindow and getOwnerDocument eslint rule in more packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. If the aim here is to add full support for shadow DOM (which will be great), this isn't as simple as adding utilities. When I say full support, I mean everything just works out of the box irrespective of the where a shadow DOM is located. And that will include much more than some utilities and will involve refactoring of certain sections.
|
||
## Help Needed | ||
|
||
The biggest help we can receive is tests, either in the form of unit tests or in the form of examples of real life applications/setups that we can turn into unit tests. The more tests we have, the less likely we will break anything moving forward after the initial effort is complete. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to avoid maintaining a fork so we will try to do our best here. Right now we use patches which are a nightmare during upgrades.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what this has to do with the "help needed" section? Are you just saying it will be hard to create tests and examples?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for not being clear. I meant we will like to help here as much as possible so that we do not have to maintain a fork. At the end of the day, we want shadow DOM support to land up here.
|
||
## Open Questions | ||
|
||
* How to actually define the limitations of our support? See Introduction, it's missing a final sentence with this information. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A possible classification:
Container components that can have anything vs create name components such as RadioGroup that don't allow shadowdom's inside them
rfcs/2025-shadow-dom-support.md
Outdated
|
||
## Motivation | ||
|
||
As Web Components have become more prominent and more libraries and applications use them, we have encountered friction for people trying to adopt or use our libraries alongside others. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I'll reframe a bit, I was using Web Components as a bit of a stand-in term for shadow dom, but this is more accurate
I think we are potentially over simplifying by stating that solving shadow dom will solve iframes. They are two fundamentally different technologies even if they have overlap in terms of problems they solve.
See for example the need for
addWindowFocusTracking(iframeRoot); |
This is not needed for Shadow DOM. If we only worked on supporting Shadow DOM, this would be missed. That is because events inside an iframe will not appear outside the frame. While for Shadow DOM, events still have a capture phase and bubble phase outside of the Shadow root.
There will be other cases where behaviour differs between the two technologies.
|
||
As mentioned earlier, there are proposed parts to this initiative: | ||
|
||
1. Custom React Testing Library Renderer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what this comment has to do with us? The RFC is for what we need to do to support shadow dom in our library.
I'm also suggesting that we run the same tests both with and without shadow DOM
we should create a custom React Testing Library renderer for our unit tests which can wrap each test's rendered dom in a shadow root.
... without needing to write many specific tests.
There will need to be specific tests as well, but they can be added as edge cases are discovered. For now I'd like to get all of our current tests running both ways.
|
||
In addition, contributions may occur for a little while until those teams have their needs met. However, it should be assumed that there will be further work to complete the goals as outlined here. | ||
|
||
Another concern is that the current approach is, for lack of a better word, hacky. This is because we are accessing and manipulating the Shadow DOM in ways that it wasn't really intended. If we were to rewrite our library today, there are other ways we'd solve these issues which would respect more of the concept of the Shadow DOM and its purpose. What we do here and now may complicate a future where we have different APIs to support this vision of what support would ideally look like. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly, what happens in the case of nested shadow doms though? Would we expect people to addWindowFocusTracking
equivalent for each root and each hook/function that needs it? Would components need to accept a root element to pass down to hooks? context?
This wouldn't work for closed roots. This is why we want to re-think some of the ways parts of our library work. For example, FocusScope moves focus around for you when it's contain=true
. This can't move into closed shadow roots, which is why the video
tag breaks our FocusScope at the moment in certain cases. Instead, if we moved to a sentinel-based approach, we could let the browser handle the tab movement.
|
||
## Open Questions | ||
|
||
* How to actually define the limitations of our support? See Introduction, it's missing a final sentence with this information. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is ambiguous
all new code is compatible
Does that mean it works in an application that has a single shadow dom at the root? that it can use video
anywhere? that it can have 3rd party web components anywhere? that it can have shadow roots anywhere?
What if the new code is a new feature in an existing component or hook that has no support? what if that hook depends on lower hooks that don't have support and changing those hooks would also change how other components work.
It's a lofty goal and I think we should aim for support of everything. But it has to be moderated with the cost of implementation and ongoing support.
I don't believe this is true
it will be just about using a set of utilities
as I mentioned earlier, in order to support closed root (as an example), we have to rethink how many components and hooks are implemented.
I agree with this
We can start with the getOwnerWindow and getOwnerDocument eslint rule in more packages.
Closes
✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project: